#pragma once

#include <pthread.h>
//mutex(C++11)/recursive_mutex(C++11)/timed_mutex(C++11)/recursive_timed_mutex(C++11)/unique_lock(C++11)/lock_guard(C++11)/scoped_lock(C++17)
#include <mutex>
#include <condition_variable>
#if __cplusplus > 201103L
//shared_timed_mutex(C++14)/shared_mutex(C++17)/shared_lock(C++14)
#include <shared_mutex>
#endif
#if __cplusplus > 201703L
//counting_semaphore(C++20)/binary_semaphore(C++20)
#include <semaphore>
#endif
#include <string>
#include <stdexcept>
#include <limits.h>

#if defined(__ANDROID__)
#define SITE_RWLOCK_INITIALIZER PTHREAD_RWLOCK_INITIALIZER
#else
//写锁优先, see PTHREAD_RWLOCK_PREFER_WRITER_NONRECURSIVE_NP
#define SITE_RWLOCK_INITIALIZER PTHREAD_RWLOCK_WRITER_NONRECURSIVE_INITIALIZER_NP
#endif

//提供一个宏来跟踪加锁的行号, 解锁的是真没法打印行号
#define SITE_RWLOCK_TRACE 0

#if SITE_RWLOCK_TRACE && defined(__has_include) && __has_include("spdlog_helper.h")
#include "spdlog_helper.h"
#else
#undef SITE_RWLOCK_TRACE
#define SITE_RWLOCK_TRACE 0
#endif

#if SITE_RWLOCK_TRACE
#define SITE_RWLOCK(val, p_mutex, write_lock) LOG_INFO("Create lock with {:016X}", (intptr_t)&(p_mutex)); servicesite::pthread_rwlock_guard val(p_mutex, write_lock);
#else
#define SITE_RWLOCK(val, p_mutex, write_lock) servicesite::pthread_rwlock_guard val(p_mutex, write_lock);
#endif

namespace servicesite {
    struct pthread_rwlock_guard;

    struct rwlock_holder
    {
        pthread_rwlock_t _mutex = SITE_RWLOCK_INITIALIZER;
    };
    
    struct lock_exception : std::logic_error
    {
        lock_exception(void* sender, const std::string& msg) : std::logic_error(msg) {
#if SITE_RWLOCK_TRACE
            LOG_WARN("lock_exception({:016X}): {}", (intptr_t)sender, msg);
#endif
        }
    };
    
    //see lock_guard and unique_lock
    struct pthread_rwlock_guard
    {
        pthread_rwlock_guard(pthread_rwlock_t& p_mutex, bool write_lock)
            : _mutex(&p_mutex), _locked(false), _write_lock(write_lock)
        {
#if SITE_RWLOCK_TRACE
            LOG_WARN("create pthread_rwlock_guard({:016X}) with ({:016X}), {}", (intptr_t)this, (intptr_t)&p_mutex, _write_lock);
#endif
            lock();
        }

        pthread_rwlock_guard(rwlock_holder& p_mutex, bool write_lock)
            : pthread_rwlock_guard(p_mutex._mutex, write_lock)
        {
        }

        void unlock(bool no_throw = false);
        void lock();
        ~pthread_rwlock_guard() {
            unlock(true);
        }

        pthread_rwlock_guard(pthread_rwlock_guard&&) = default;
        pthread_rwlock_guard(const pthread_rwlock_guard&) = delete;
        pthread_rwlock_guard& operator=(const pthread_rwlock_guard&) = delete;

private:
        pthread_rwlock_t* _mutex;
        bool _locked;
        const bool _write_lock;
    };

    template <typename Function>
    struct defer_cleanup_t {
        const Function f;
        defer_cleanup_t(Function f) : f(f) {}
        ~defer_cleanup_t() { f(); }
    };

    template <typename Function>
    defer_cleanup_t<Function> defer_cleanup(Function f) {
        return defer_cleanup_t<Function>(f);
    }

    //提供一个通过TLS实现, 支持简单锁递归的版本(不支持锁升级)
    struct rwlock_recursive_holder
    {
        struct tls_data
        {
            int reader_cnt;
            int writer_cnt;
            pthread_t tid;
        };

        pthread_rwlock_t _mutex = SITE_RWLOCK_INITIALIZER;

private:
        pthread_key_t _tls_key;

        static void _cleanup_tls_data(void* ptr) {
            tls_data* data = (tls_data*)ptr;
            delete data;
        }

public:
        tls_data* get_or_create_tls_data() {
            tls_data* data;
            void* ptr = pthread_getspecific(_tls_key);
            if (ptr == nullptr) {
                data = new tls_data();
                data->tid = pthread_self();
                int res = pthread_setspecific(_tls_key, data);
                if (res != 0) {
                    delete data;
                    throw lock_exception(this, "failed to call pthread_setspecific: " + std::to_string(res));
                }
            } else {
                data = (tls_data*)ptr;
            }
            return data;
        }

        rwlock_recursive_holder() {
            int res = pthread_key_create(&_tls_key, _cleanup_tls_data);
            if (res != 0) {
                _tls_key = PTHREAD_KEYS_MAX;
                throw lock_exception(this, "failed to call pthread_key_create: " + std::to_string(res));
            }
        }

        ~rwlock_recursive_holder() {
            if (_tls_key != PTHREAD_KEYS_MAX)
                pthread_key_delete(_tls_key);
        }
    };
    
    //see lock_guard and unique_lock
    struct pthread_rwlock_recursive_guard
    {
        pthread_rwlock_recursive_guard(rwlock_recursive_holder& p_mutex, bool write_lock)
            : _data(p_mutex.get_or_create_tls_data()), _mutex(&p_mutex._mutex), _locked(false), _write_lock(write_lock)
        {
#if SITE_RWLOCK_TRACE
            LOG_WARN("create pthread_rwlock_recursive_guard({:016X}) with ({:016X}), {}", (intptr_t)this, (intptr_t)&p_mutex, _write_lock);
#endif
            lock();
        }

        void unlock(bool no_throw = false);
        void lock();
        ~pthread_rwlock_recursive_guard() {
            unlock(true);
        }

        pthread_rwlock_recursive_guard(pthread_rwlock_recursive_guard&&) = default;
        pthread_rwlock_recursive_guard(const pthread_rwlock_recursive_guard&) = delete;
        pthread_rwlock_recursive_guard& operator=(const pthread_rwlock_recursive_guard&) = delete;

private:
        rwlock_recursive_holder::tls_data* _data;
        pthread_rwlock_t* _mutex;
        bool _locked;
        const bool _write_lock;
    };
}